package usbipserversrv

import (
	log "github.com/sirupsen/logrus"
	"go.uber.org/atomic"
	"net"
	"time"
	"usbipproxy/common"
	"usbipproxy/domain/service"
	"usbipproxy/pb"
)

type UsbipServerSrvServiceImpl struct {
	conn         net.Conn
	serverAddr   string
	msgNotifySvc service.MsgNotifyService
	//bufPool      sync.Pool
	busId         string
	sessId        string
	vendorId      string
	outMsg        chan []byte
	closed        atomic.Bool
	buf           []byte
	logger        *log.Entry
	lastHeartbeat time.Time
	notifyConnId  int64
}

func NewUsbipServerSrvServiceImpl(serverAddr, busId, vendorId, sessId string, notifyConnId int64, msgNotifySvc service.MsgNotifyService) UsbipServerSrvService {
	return &UsbipServerSrvServiceImpl{
		serverAddr:    serverAddr,
		busId:         busId,
		vendorId:      vendorId,
		sessId:        sessId,
		msgNotifySvc:  msgNotifySvc,
		buf:           make([]byte, 60*1024),
		outMsg:        make(chan []byte, 65536),
		logger:        log.WithField("bus_id", busId).WithField("sess_id", sessId).WithField("vendor_id", vendorId),
		lastHeartbeat: time.Now(),
		notifyConnId:  notifyConnId,
	}

	//bufPool: sync.Pool{
	//	New: func() interface{} {
	//return make([]byte, 60*1024) // 8KB的缓冲区
	//	},
	//},
}

func (impl *UsbipServerSrvServiceImpl) GetNotifyConnId() int64 {
	if impl == nil {
		return 0
	}
	return impl.notifyConnId
}

func (impl *UsbipServerSrvServiceImpl) GetBusId() string {
	if impl == nil {
		return ""
	}
	return impl.busId
}

func (impl *UsbipServerSrvServiceImpl) GetVendorId() string {
	if impl == nil {
		return ""
	}
	return impl.vendorId
}

func (impl *UsbipServerSrvServiceImpl) GetSessId() string {
	if impl == nil {
		return ""
	}
	return impl.sessId
}

func (impl *UsbipServerSrvServiceImpl) RecvHeartbeatMsg() error {
	if impl == nil {
		return nil
	}
	impl.lastHeartbeat = time.Now()
	log.Infof("UsbipServerSrvServiceImpl recv heartbeat msg")
	return nil
}

func (impl *UsbipServerSrvServiceImpl) RecvMsg(msg []byte) error {
	if impl == nil {
		return nil
	}
	if impl.closed.Load() {
		log.Infof("UsbipServerSrvServiceImpl have been closed")
		return nil
	}
	impl.lastHeartbeat = time.Now()
	select {
	case impl.outMsg <- msg:
		impl.logger.Debugf("UsbipServerSrvServiceImpl.RecvMsg  len(msg):%v", len(msg))
	default:
		impl.logger.Warnf("UsbipServerSrvServiceImpl.RecvMsg chan full")
	}

	return nil
}

func (impl *UsbipServerSrvServiceImpl) FlushAllOutMsg() error {
	if impl == nil {
		return nil
	}
	for {
		select {
		case <-impl.outMsg:
		default:
			return nil
		}
	}
}

func (impl *UsbipServerSrvServiceImpl) Stop() {
	if impl == nil {
		return
	}
	if !impl.closed.CompareAndSwap(false, true) {
		return
	}
	impl.logger.Infof("UsbipServerSrvServiceImpl Stop")
	if impl.conn != nil {
		impl.conn.Close()
		impl.conn = nil
	}
	/*
		impl.msgNotifySvc.SendMsg(&pb.ProxyMsg{
			MsgType: pb.MsgType_SERVER_DETACH,
			Base: &pb.BaseParam{
				//ReqId:     impl.sessId,
				Timestamp: time.Now().UnixNano(),
			},
			Param: &pb.ProxyMsg_ServerDetachParam{ServerDetachParam: &pb.ServerDetachParam{
				BusId:  impl.busId,
				SessId: impl.sessId,
			}},
		})
	*/
	//impl.RecvMsg(nil)
}

func (impl *UsbipServerSrvServiceImpl) Start() error {
	if impl == nil {
		return nil
	}
	log.Infof("UsbipServerSrvServiceImpl Start client connect addr:%v", impl.serverAddr)
	conn, err := net.Dial("tcp", impl.serverAddr)
	if err != nil {
		impl.logger.Infof("UsbipServerSrvServiceImpl connect %v err:%v", impl.serverAddr, err)
		return err
	}
	// 设置 TCP NoDelay 选项
	if tcpConn, ok := conn.(*net.TCPConn); ok {
		//tcpConn.SetNoDelay(true)
		tcpConn.SetReadBuffer(1024 * 1024)
		tcpConn.SetWriteBuffer(1024 * 1024)
	}
	impl.conn = conn
	log.Infof("UsbipServerSrvServiceImpl Start client connect addr:%v succ", impl.serverAddr)

	// 启动发送数据到服务器的goroutine
	go func() {
		defer func() {
			impl.Stop()
			impl.FlushAllOutMsg()
		}()
		defer func() {
			termMsg1 := &pb.ProxyMsg{
				MsgType: pb.MsgType_TO_CLIENT_ATTACH_OVER,
				Base: &pb.BaseParam{
					ToId: impl.notifyConnId,
				},
				Param: &pb.ProxyMsg_ToServerAttachOverParam{ToServerAttachOverParam: &pb.ToServerAttachOverParam{
					SessId:   impl.sessId,
					BusId:    impl.busId,
					VendorId: impl.vendorId,
				}},
			}
			impl.msgNotifySvc.SendMsg(termMsg1)
		}()
		for msg := range impl.outMsg {
			impl.logger.Debugf("UsbipServerSrvServiceImpl receive len(msg):%v", len(msg))
			if len(msg) == 0 {
				break
			}
			if err := impl.writeBinaryData(conn, msg); err != nil {
				impl.logger.Warnf("handleConnection Write error  %v\n", err)
				return
			}

		}
	}()

	//check heartbeat
	go func() {
		ticker := time.NewTicker(time.Second)
		defer ticker.Stop()

		n := 0
		for !impl.closed.Load() {
			select {
			case <-ticker.C:
				now := time.Now()
				if now.After(impl.lastHeartbeat.Add(time.Second * 30 * 5 / 2)) {
					log.Infof("UsbipServerSrvServiceImpl heartbeat timeout todo")
					impl.Stop()
					//impl.lastHeartbeat = time.Now()
					return
				}
				if n%30 == 0 {
					impl.msgNotifySvc.SendMsg(&pb.ProxyMsg{
						MsgType: pb.MsgType_HEARTBEAT,
						Base: &pb.BaseParam{
							ToId: impl.notifyConnId,
						},
						Param: &pb.ProxyMsg_HeartbeatParam{HeartbeatParam: &pb.HeartbeatParam{
							BusId:  impl.busId,
							SessId: impl.sessId,
						}},
					})
				}
				n++
			}
		}
	}()

	//seq := int64(0)
	for {
		buf := impl.buf[:]
		n, err := impl.conn.Read(buf)
		if err != nil {
			impl.logger.Warnf("UsbipServerSrvServiceImpl Read error: %v", err)
			break
		}

		if n == 0 {
			impl.logger.Infof("UsbipServerSrvServiceImpl closed by server")
			break
		}
		impl.logger.Debugf("UsbipServerSrvServiceImpl  read n:%d", n)
		if n > 0 {
			// 创建新切片并复制数据
			data := make([]byte, n)
			copy(data, buf[:n])
			impl.msgNotifySvc.SendMsg(&pb.ProxyMsg{
				MsgType: pb.MsgType_TO_CLIENT_ATTACH_DATA,
				Base: &pb.BaseParam{
					ToId: impl.notifyConnId,
				},
				Param: &pb.ProxyMsg_ToClientAttachDataParam{ToClientAttachDataParam: &pb.ToClientAttachDataParam{
					BusId:  impl.busId,
					SessId: impl.sessId,
					Data:   data,
				}},
			})
		}
	}

	impl.RecvMsg(nil)

	return nil
}

func (impl *UsbipServerSrvServiceImpl) writeBinaryData(conn net.Conn, data []byte) error {
	if impl == nil {
		return nil
	}
	// 写入实际数据
	writeTimeout := 30 * time.Second
	deadline := time.Now().Add(writeTimeout)
	if err := conn.SetWriteDeadline(deadline); err != nil {
		impl.logger.Warnf("UsbipServerSrvServiceImpl SetWriteDeadline fail: %v", err)
		return err
	}
	n, err := common.BlockingWrite(impl.conn, data)
	if err != nil {
		impl.logger.Warnf("UsbipServerSrvServiceImpl writeBinaryData error  %v\n", err)
		return err
	}

	if n != len(data) {
		impl.logger.Warnf("UsbipServerSrvServiceImpl writeBinaryData failed:%v:%v", len(data), n)
	}

	impl.logger.Debugf("UsbipServerSrvServiceImpl writeBinaryData n:%d len(data):%v",
		n, len(data))

	return nil
}
